package com.huanxing.cloud.mall.api.handler.impl;

import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huanxing.cloud.common.core.constant.CacheConstants;
import com.huanxing.cloud.common.core.constant.SecurityConstants;
import com.huanxing.cloud.common.core.entity.Result;
import com.huanxing.cloud.mall.api.service.IDistributionUserService;
import com.huanxing.cloud.mall.api.service.IUserInfoService;
import com.huanxing.cloud.mall.api.utils.HxTokenHolder;
import com.huanxing.cloud.mall.common.constant.MallUserConstants;
import com.huanxing.cloud.mall.common.dto.HxTokenInfo;
import com.huanxing.cloud.mall.common.dto.UserLoginDTO;
import com.huanxing.cloud.mall.common.entity.UserInfo;
import com.huanxing.cloud.mall.common.feign.FeignWxUserService;
import com.huanxing.cloud.miniapp.common.dto.WxUserDTO;
import com.huanxing.cloud.miniapp.common.entity.WxUser;
import com.huanxing.cloud.security.handler.HxBusinessException;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

@Component("WX_MA_PHONE_LOGIN")
@AllArgsConstructor
public class WechatPhoneLoginHandler extends AbstractLoginHandler {

	private final IUserInfoService userInfoService;

	private final FeignWxUserService feignWxUserService;

	private final RedisTemplate<String, String> redisTemplate;

	private final IDistributionUserService distributionUserService;

	@Override
	public void before(UserLoginDTO userLoginDTO) {
	}

	@Override
	public UserInfo doLogin(UserLoginDTO userLoginDTO) {

		HxTokenInfo hxTokenInfo = HxTokenHolder.getTokenInfo();
		String key = CacheConstants.MALL_USER_TOKEN + userLoginDTO.getHxToken();

		WxUserDTO wxUserDTO = new WxUserDTO();
		wxUserDTO.setEncryptedData(userLoginDTO.getEncryptedData());
		wxUserDTO.setSessionKey(hxTokenInfo.getSessionKey());
		wxUserDTO.setIv(userLoginDTO.getIv());
		wxUserDTO.setClientType(userLoginDTO.getClientType());
		wxUserDTO.setAppId(userLoginDTO.getAppId());

		Result<WxMaPhoneNumberInfo> result = feignWxUserService.getPhoneNumberInfo(wxUserDTO,
				SecurityConstants.SOURCE_IN);
		if (!result.isOk()) {
			throw new RuntimeException(result.getMsg());
		}
		WxMaPhoneNumberInfo wxMaPhoneNumberInfo = result.getData();
		String phone = wxMaPhoneNumberInfo.getPhoneNumber();
		UserInfo userInfo = userInfoService.getOne(Wrappers.<UserInfo>lambdaQuery().eq(UserInfo::getPhone, phone));
		if (ObjectUtil.isNull(userInfo)) {
			userInfo = new UserInfo();
			userInfo.setUserGrade(MallUserConstants.USER_GRADE_0);
			userInfo.setAvatarUrl(MallUserConstants.DEFAULT_AVATAR_URL);
			userInfo.setUserSource(userLoginDTO.getClientType());
			userInfo.setAccountBalance(BigDecimal.ZERO);
		}
		Result<WxUser> wxUserResult = feignWxUserService.getById(hxTokenInfo.getWxUserId(),
				SecurityConstants.SOURCE_IN);
		if (Boolean.FALSE.equals(wxUserResult.isOk())) {
			throw new HxBusinessException(wxUserResult.getMsg());
		}
		WxUser wxUser = wxUserResult.getData();

		if (StrUtil.isBlank(userInfo.getAvatarUrl())) {
			userInfo.setAvatarUrl(wxUser.getAvatarUrl());
		}

		if (StrUtil.isBlank(userInfo.getNickName())) {
			userInfo.setNickName(wxUser.getNickName());
		}
		userInfo.setPhone(phone);
		userInfoService.saveOrUpdateUser(userInfo);

		wxUser.setMallUserId(userInfo.getId());
		wxUser.setPhone(phone);

		feignWxUserService.saveOrUpdate(wxUser, SecurityConstants.SOURCE_IN);
		// 更新redis中的token信息
		hxTokenInfo.setMallUserId(userInfo.getId());
		redisTemplate.opsForValue()
			.set(key, JSONUtil.toJsonStr(hxTokenInfo), CacheConstants.TOKEN_TIME, TimeUnit.HOURS);
		userInfo.setHxToken(StrUtil.removeAll(key, CacheConstants.MALL_USER_TOKEN));
		return userInfo;
	}

	@Override
	public void updateUser(UserInfo userInfo) {
		userInfoService.updateById(userInfo);
	}

	@Override
	public void distributionBindUser(UserInfo userInfo) {
		distributionUserService.bindUser(userInfo);
	}

}
